#include "CFacebookClient.h"

#define MTA_PLAYER_LIMIT		(128)
#define SAMP_PLAYER_LIMIT		(500)

#define MAX_PLAYERS		(MTA_PLAYER_LIMIT)

CFacebookClient
	*g_FBPool[MAX_PLAYERS];

const std::string
	MTAFBCHAT_VERSION_TEXT = "1.0";

CFacebookClient::CFacebookClient(PlayerIdentifier Player, const tchar::tstring &Username, const tchar::tstring &Password)																					
{
	//m_RosterManager = new gloox::RosterManager(&fbClient);
	//if(!m_RosterManager)
	//{
	//	printf("fail to allocate roster");
	//}
	if(!Player)
	{
		throw;
	}
	else
	{
		m_MyID = Player;
	}
	m_Self.setJID(Username+"@chat.facebook.com");
	fbClient = new gloox::Client(m_Self, Password);
	if(!fbClient)
	{
		throw;
	}
	m_RosterManager = fbClient->rosterManager();
	if(!m_RosterManager)
	{
		throw;
	}
	m_vManager = new VCardManager(fbClient);
	if(!m_vManager)
	{
		throw;
	}
	fbClient->registerMessageHandler(this);
	fbClient->registerConnectionListener(this);
	fbClient->setTls(gloox::TLSDisabled);
	m_RosterManager->registerRosterListener(this, false);
	//fbClient.registerStanzaExtension(new DelayedDelivery(new Tag("")));

	fbClient->disco()->setIdentity("client", "pc");
	fbClient->disco()->setVersion("MTA-FacebookChat", MTAFBCHAT_VERSION_TEXT);
	if(fbClient->connect(false))
	{
		m_MyData = new CThreadData;
		m_MyData->bAbortThread = false;
		Start(m_MyData);
		Sleep(5);
	}
}

bool CFacebookClient::IsConnected()
{
	return fbClient->authed();
}

void *CFacebookClient::GetUserData()
{
	return m_MyID;
}

int	CFacebookClient::Execute(CThreadData *pData)
{
	try
	{
		ConnectionError
			ce = ConnNoError;
		while(ce == ConnNoError && !pData->bAbortThread)
		{
			ce = fbClient->recv();
			Sleep(5);
		}
	}
	catch(...)
	{
		return 0;
	}
	return 0;
}

void CFacebookClient::handleMessage(const gloox::Message &sender, gloox::MessageSession *session)
{
	tchar::tstring
		sMessage = sender.body();
	if(!sMessage.empty() && IsConnected())
	{
		std::vector<tchar::tstring>
			args;
		args.push_back(sender.from().username());
		args.push_back(sMessage);
		const gloox::DelayedDelivery
			*time = sender.when();
		if(time)
		{
			args.push_back(sender.when()->stamp());
		}
		CFunctions::triggerEvent("onChatMessage", m_MyID, &args);
	}
}

bool CFacebookClient::SendMessage(gloox::JID Receiver, tchar::tstring sMessage)
{
	if(IsConnected())
	{
		std::vector<tchar::tstring>
			args;
		args.push_back(Receiver.bare());
		args.push_back(sMessage);
		gloox::Message
			msg(gloox::Message::Chat, Receiver, sMessage);
		const DelayedDelivery
			*time = msg.when();
		if(time)
		{
			tchar::tstringstream
				timeString;
			timeString << time->stamp();
			args.push_back(timeString.str());
		}
		if(CFunctions::triggerEvent("onClientSendMessage", m_MyID, &args))
		{
			fbClient->send(msg);
			return 1;
		}
	}
	return 0;
}

void CFacebookClient::Logout(bool Enforce)
{
	if(Enforce || IsConnected())
	{
		Stop();
		if(fbClient)
		{
			fbClient->disconnect();
			delete fbClient;
			fbClient = 0;
		}
		if(m_vManager)
		{
			m_vManager->cancelVCardOperations(this);
		}
		if(m_MyData)
		{
			delete m_MyData;
			m_MyData = 0;
		}
	}
}

void CFacebookClient::onConnect()
{
	if(!CFunctions::triggerEvent("onClientConnect", m_MyID))
	{
		// logout if event is canceled
		Logout(true);
		return;
	}
	//m_vManager.fetchVCard(m_Self, this);
}

void CFacebookClient::onDisconnect(ConnectionError e)
{
	std::vector<tchar::tstring>
		args;
	tchar::tstringstream
		errorString;
	errorString << e;
	args.push_back(errorString.str());
	CFunctions::triggerEvent("onClientDisconnect", m_MyID, &args);
}

void CFacebookClient::handleVCard(const JID &jid, const gloox::VCard *v)
{
	(void)jid;
	delete v;
}

void CFacebookClient::handleVCardResult(VCardContext context, const JID &jid, StanzaError se)
{
	if(se != gloox::StanzaErrorUndefined)
	{
		printf("%s VCard for user %s failed with error %u", context == gloox::VCardHandler::StoreVCard ? "Storing" : "Fetching", jid.bare().c_str(), se);
	}
	//m_vManager->fetchVCard(jid, this);
}

void CFacebookClient::handleItemSubscribed( const JID& jid )
{
}

void CFacebookClient::getVCard(const tchar::tstring &user)
{
	m_vManager->fetchVCard(gloox::JID(user), this);
}

void CFacebookClient::handleItemAdded( const JID& jid )
{
	printf( "added %s\n", jid.bare().c_str() );
}

void CFacebookClient::handleItemUnsubscribed( const JID& jid )
{
	printf( "unsubscribed %s\n", jid.bare().c_str() );
}

void CFacebookClient::handleItemRemoved(const gloox::JID &jid)
{
	printf( "removed %s\n", jid.bare().c_str() );
}

void CFacebookClient::handleItemUpdated(const gloox::JID &jid)
{
	printf( "updated %s\n", jid.bare().c_str() );
}

bool CFacebookClient::onTLSConnect(const gloox::CertInfo &info)
{
	return true;
}

void CFacebookClient::handleRoster(const Roster &roster)
{
	Roster::const_iterator
		it = roster.begin();
	for(; it != roster.end(); ++it)
	{
		std::vector<tchar::tstring>
			args;
		args.push_back(it->second->name());
		//std::string
		//	temp = it->second->jid();
		// deletes @chat.facebook.com as we don't need it
		//args.push_back(it->second->jid().substr(0, it->second->jid().find('@')));
		args.push_back(it->first);
		CFunctions::triggerEvent("onRosterUpdate", m_MyID, &args);
		// TODO: add groups support
		/*
		StringList 
			g = (*it).second->groups();
		StringList::const_iterator 
			it_g = g.begin();
		for(; it_g != g.end(); ++it_g)
		{
			printf( "\tgroup: %s\n", (*it_g).c_str() );
		}
		RosterItem::ResourceMap::const_iterator rit = (*it).second->resources().begin();
		for(; rit != (*it).second->resources().end(); ++rit)
		{
			printf( "resource: %s\n", (*rit).first.c_str() );
		}
		*/
	}
}
void CFacebookClient::handleRosterError(const gloox::IQ &iq)
{
}

void CFacebookClient::handleRosterPresence(const gloox::RosterItem &item, const std::string &resource, Presence::PresenceType presence, const std::string &msg)
{
	std::vector<tchar::tstring>
		args;
	std::ostringstream
		presence_stream;
	args.push_back(item.jid());
	args.push_back(resource);
	presence_stream << presence;
	args.push_back(presence_stream.str());
	CFunctions::triggerEvent("onPresenceUpdate", m_MyID, &args);
}

void CFacebookClient::handleSelfPresence(const gloox::RosterItem &item, const std::string &resource, Presence::PresenceType presence, const std::string &msg)
{
	if(resource == fbClient->resource())
	{
		std::vector<tchar::tstring>
			args;
		args.push_back(item.jid().c_str());
		args.push_back(resource.c_str());
		std::ostringstream
			presenceText;
		presenceText << presence;
		args.push_back(presenceText.str());
		CFunctions::triggerEvent("onClientChangeStatus", m_MyID, &args);
	}
}

bool CFacebookClient::handleSubscriptionRequest(const gloox::JID &jid, const std::string &msg)
{
	return false;
}

bool CFacebookClient::handleUnsubscriptionRequest(const JID &jid, const std::string &msg)
{
	return false;
}

void CFacebookClient::handleNonrosterPresence(const gloox::Presence &presence)
{
}

CFacebookClient::~CFacebookClient()
{
	Logout(true);
}